package org.zjx.util;

import org.zjx.entity.Rect;

import java.awt.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 随机数工具类
 * 提供多种随机数生成功能
 */
public class RandomUtil {

    /**
     * 1. 生成指定范围内的随机整数（包含正负值）
     * @param min 最小值（可正可负）
     * @param max 最大值（可正可负）
     * @return 介于min和max之间的随机整数（包含min和max）
     * @throws IllegalArgumentException 如果min > max
     */
    public static int randomIntBetween(int min, int max) {
        if (min > max) {
            throw new IllegalArgumentException("min must be less than or equal to max");
        }
        return ThreadLocalRandom.current().nextInt(min, max + 1);
    }

    /**
     * 2. 生成指定范围内的正整数
     * @param max 最大值（必须为正数）
     * @return 介于0和max之间的随机正整数（包含0，不包含max）
     * @throws IllegalArgumentException 如果max <= 0
     */
    public static int randomPositiveInt(int max) {
        if (max <= 0) {
            throw new IllegalArgumentException("max must be positive");
        }
        return ThreadLocalRandom.current().nextInt(max);
    }

    /**
     * 根据概率分布从集合中随机选取一个元素
     * @param elements 元素集合
     * @param ranges 每个元素对应的概率范围区间（每个区间为[min, max)）
     * @param <T> 元素类型
     * @return 随机选中的元素
     * @throws IllegalArgumentException 如果参数不合法
     */
    public static <T> T randomElementByProbability(Collection<T> elements, List<double[]> ranges) {
        if (elements == null || ranges == null || elements.size() != ranges.size()) {
            throw new IllegalArgumentException("Elements and ranges must be non-null and of same size");
        }

        // 检查空集合
        if (elements.isEmpty()) {
            throw new IllegalArgumentException("Elements collection cannot be empty");
        }

        // 验证概率范围是否合法
        double total = 0;
        double lastMax = 0;

        for (double[] range : ranges) {
            if (range.length != 2) {
                throw new IllegalArgumentException("Each range must have exactly 2 values");
            }
            if (range[0] < 0 || range[1] < range[0]) {
                throw new IllegalArgumentException("Invalid probability range: min must be >= 0 and max > min");
            }
            if (range[0] < lastMax) {
                throw new IllegalArgumentException("Probability ranges must be in order and non-overlapping");
            }
            lastMax = range[1];
            total += range[1] - range[0];
        }

        // 允许1e-10的误差范围
        if (Math.abs(total - 1.0) > 1e-10) {
            throw new IllegalArgumentException(
                    String.format("Probability ranges must sum to 1.0 (actual: %.10f)", total));
        }

        // 生成随机数并选择对应元素
        double random = ThreadLocalRandom.current().nextDouble();
        double accumulated = 0;

        Iterator<T> elementIter = elements.iterator();
        Iterator<double[]> rangeIter = ranges.iterator();

        while (elementIter.hasNext() && rangeIter.hasNext()) {
            T element = elementIter.next();
            double[] range = rangeIter.next();
            double rangeWidth = range[1] - range[0];

            // 处理浮点数精度问题
            if (random < accumulated + rangeWidth + 1e-10) {
                return element;
            }
            accumulated += rangeWidth;
        }

        // 如果由于浮点精度问题仍然没有命中，返回最后一个元素
        return getLastElement(elements);
    }

    private static <T> T getLastElement(Collection<T> collection) {
        Iterator<T> iterator = collection.iterator();
        T last = null;
        while (iterator.hasNext()) {
            last = iterator.next();
        }
        return last;
    }

    /**
     * 3. 简化版 - 根据权重随机选择元素
     * @param elements 元素集合
     * @param weights 每个元素的权重（必须为正数）
     * @param <T> 元素类型
     * @return 随机选中的元素
     * @throws IllegalArgumentException 如果参数不合法
     */
    public static <T> T randomElementByWeight(List<T> elements, List<Double> weights) {
        if (elements == null || weights == null || elements.size() != weights.size()) {
            throw new IllegalArgumentException("Elements and weights must be non-null and of same size");
        }

        // 计算总权重
        double totalWeight = weights.stream().mapToDouble(Double::doubleValue).sum();
        if (totalWeight <= 0) {
            throw new IllegalArgumentException("Total weight must be positive");
        }

        // 生成随机数并选择对应元素
        double random = ThreadLocalRandom.current().nextDouble() * totalWeight;
        double accumulated = 0;

        for (int i = 0; i < elements.size(); i++) {
            accumulated += weights.get(i);
            if (random <= accumulated) {
                return elements.get(i);
            }
        }

        // 理论上不应该执行到这里
        return elements.get(elements.size() - 1);
    }

    /**
     * 生成随机布尔值
     * @return 随机true或false
     */
    public static boolean randomBoolean() {
        return ThreadLocalRandom.current().nextBoolean();
    }

    /**
     * 生成指定范围内的随机浮点数
     * @param min 最小值
     * @param max 最大值
     * @return 介于min和max之间的随机浮点数
     */
    public static double randomDoubleBetween(double min, double max) {
        if (min > max) {
            throw new IllegalArgumentException("min must be less than or equal to max");
        }
        return ThreadLocalRandom.current().nextDouble(min, max);
    }

    /**
     * 在大矩形区域内随机生成一个点，避开所有排除的小矩形区域
     * @param largeRect 大矩形区域
     * @param excludedRects 需要避开的小矩形集合
     * @return 随机生成的Point，如果无法找到合适位置则返回null
     */
    public static Point randomPointExcludingRects(Rect largeRect, Collection<Rect> excludedRects) {
        // 最大尝试次数，避免无限循环
        int maxAttempts = 100;
        int attempts = 0;

        while (attempts++ < maxAttempts) {
            // 在大矩形内随机生成一个点
            Point randomPoint = new Point(
                    randomIntBetween(largeRect.getLeft(), largeRect.getRight()),
                    randomIntBetween(largeRect.getTop(), largeRect.getBottom())
            );

            // 检查是否在任何排除矩形内
            boolean overlaps = false;
            for (Rect excluded : excludedRects) {
                if (excluded.contains(randomPoint)) {
                    overlaps = true;
                    break;
                }
            }

            // 如果不重叠则返回
            if (!overlaps) {
                return randomPoint;
            }
        }

        // 多次尝试后仍未找到合适位置
        return null;
    }

    public static void main(String[] args) {
        // 1. 正负范围随机数
        int randomInRange = RandomUtil.randomIntBetween(-50, 50);
        System.out.println("随机数(-50到50): " + randomInRange);

// 2. 正范围随机数
        int positiveRandom = RandomUtil.randomPositiveInt(100);
        System.out.println("随机正整数(0-99): " + positiveRandom);

// 3.1 概率区间选择
        List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子");
        List<double[]> probabilities = Arrays.asList(
                new double[]{0.0, 0.5},   // 苹果 50%
                new double[]{0.5, 0.8},    // 香蕉 30%
                new double[]{0.8, 1.0}     // 橙子 20%
        );
        String selectedFruit = RandomUtil.randomElementByProbability(fruits, probabilities);
        System.out.println("按概率选择的水果: " + selectedFruit);

// 3.2 权重选择（简化版）
        List<String> colors = Arrays.asList("红", "绿", "蓝");
        List<Double> weights = Arrays.asList(0.7, 0.2, 0.1); // 红70%，绿20%，蓝10%
        String selectedColor = RandomUtil.randomElementByWeight(colors, weights);
        System.out.println("按权重选择的颜色: " + selectedColor);

// 其他方法
        boolean bool = RandomUtil.randomBoolean();
        double floatNum = RandomUtil.randomDoubleBetween(1.5, 3.5);
    }
}